/*******************************************************************************
 * Copyright (c) 2004, 2005 Elias Volanakis and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Elias Volanakis - initial API and implementation
 *******************************************************************************/
package edu.ccut.saturn.studio.wfg.part;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;

import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.ShortestPathConnectionRouter;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.gef.editpolicies.RootComponentEditPolicy;
import org.eclipse.gef.editpolicies.XYLayoutEditPolicy;
import org.eclipse.gef.requests.ChangeBoundsRequest;
import org.eclipse.gef.requests.CreateRequest;

import edu.ccut.saturn.studio.logic.model.BasicShape;
import edu.ccut.saturn.studio.wfg.command.ShapeCreateCommand;
import edu.ccut.saturn.studio.wfg.command.ShapeSetConstraintCommand;
import edu.ccut.saturn.studio.wfg.model.Shape;
import edu.ccut.saturn.studio.wfg.model.ShapesDiagram;
import edu.ccut.saturn.studio.wfg.policy.ResizaEdidPolicyNoHandle;

class DiagramEditPart extends AbstractGraphicalEditPart implements
		PropertyChangeListener {
	public void activate() {
		if (!isActive()) {
			super.activate();
			((BasicShape) getModel()).addPropertyChangeListener(this);
		}
	}

	protected void createEditPolicies() {
		installEditPolicy(EditPolicy.COMPONENT_ROLE,
				new RootComponentEditPolicy());
		installEditPolicy(EditPolicy.LAYOUT_ROLE,
				new ShapesXYLayoutEditPolicy());
	}

	protected IFigure createFigure() {
		Figure f = new FreeformLayer();
		f.setBorder(new MarginBorder(3));
		f.setLayoutManager(new FreeformLayout());

		ConnectionLayer connLayer = (ConnectionLayer) getLayer(LayerConstants.CONNECTION_LAYER);
		connLayer.setConnectionRouter(new ShortestPathConnectionRouter(f));

		return f;
	}

	public void deactivate() {
		if (isActive()) {
			super.deactivate();
			((BasicShape) getModel()).removePropertyChangeListener(this);
		}
	}

	private ShapesDiagram getCastedModel() {
		return (ShapesDiagram) getModel();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.gef.editparts.AbstractEditPart#getModelChildren()
	 */
	protected List<Shape> getModelChildren() {
		return getCastedModel().getShapes(); // return a list of shapes
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.beans.PropertyChangeListener#propertyChange(PropertyChangeEvent)
	 */
	public void propertyChange(PropertyChangeEvent evt) {
		String prop = evt.getPropertyName();
		// these properties are fired when Shapes are added into or removed from
		// the ShapeDiagram instance and must cause a call of refreshChildren()
		// to update the diagram's contents.
		if (ShapesDiagram.CHILD_ADDED_PROP.equals(prop)
				|| ShapesDiagram.CHILD_REMOVED_PROP.equals(prop)) {
			refreshChildren();
		}
	}

	/**
	 * EditPolicy for the Figure used by this edit part. Children of
	 * XYLayoutEditPolicy can be used in Figures with XYLayout.
	 * 
	 * @author Elias Volanakis
	 */
	private static class ShapesXYLayoutEditPolicy extends XYLayoutEditPolicy {

		protected Command createChangeConstraintCommand(
				ChangeBoundsRequest request, EditPart child, Object constraint) {
			if (child instanceof ShapeEditPart
					&& constraint instanceof Rectangle) {
				// return a command that can move and/or resize a Shape
				return new ShapeSetConstraintCommand((Shape) child.getModel(),
						request, (Rectangle) constraint);
			}
			return super.createChangeConstraintCommand(request, child,
					constraint);
		}

		protected Command createChangeConstraintCommand(EditPart child,
				Object constraint) {
			// not used in this example
			return null;
		}

		@SuppressWarnings("unchecked")
		protected Command getCreateCommand(CreateRequest request) {
			Object childClass = request.getNewObjectType();
		
			
			if (this.isSubclass(Shape.class, (Class) childClass)) {
				Shape shape = (Shape) request.getNewObject();
				ShapesDiagram diagram = (ShapesDiagram) getHost().getModel();
				shape.setId(diagram.getNextValidShapeId());
				
				return new ShapeCreateCommand(shape,
						diagram,
						(Rectangle) getConstraintFor(request));
			}
			
			return null;
		}

		@SuppressWarnings("unchecked")
		private boolean isSubclass(Class baseClass, Class subClass) {
			Class<?> subBase = subClass;

			do {
				subBase = subBase.getSuperclass();

				if (subBase == baseClass) {
					return true;
				}
			} while (subBase != null);

			return false;
		}
		
		// 用于改变handles的颜色.
		@Override
		protected EditPolicy createChildEditPolicy(EditPart child) {
			return new ResizaEdidPolicyNoHandle();
		}
	}
}